#include "invmat.h"

namespace umtl
{
	namespace invmat
	{
		std::wstring encoding( std::wstring str )
		{
			if( str.empty() )
				return str;

			typedef mat_t::elem_type elem_type;

			size_t bufLen = str.length() * sizeof( elem_type ) + 1;

			std::wstring result( bufLen, 0 );

			wchar_t * buf = (wchar_t*)result.c_str();

			for( size_t i=0; i<(str.length()/4); ++i )
			{
				mat_t m;

				m.a = (elem_type)str[i*4+0];
				m.b = (elem_type)str[i*4+1];
				m.c = (elem_type)str[i*4+2];
				m.d = (elem_type)str[i*4+3];

				m = !m;

				elem_type * fbuf = (elem_type*)buf;

				fbuf[i*4+0] = m.a;
				fbuf[i*4+1] = m.b;
				fbuf[i*4+2] = m.c;
				fbuf[i*4+3] = m.d;
			}

			for( size_t i=0; i<(str.length()%4); ++i )
			{
				elem_type * fbuf = (elem_type*)buf;
				fbuf[ str.length() - 1 - i ] = str[ str.length() - 1 - i ];
			}

			for( size_t i=0; i<result.length(); ++i )
			{
				result[i] ^= (wchar_t)result.length();
				result[i] = ~result[i];
			}

			return result;
		}

		std::wstring decoding( std::wstring str )
		{
			if( str.empty() )
				return str;

			for( size_t i=0; i<str.length(); ++i )
			{
				str[i] ^= (wchar_t)str.length();
				str[i] = ~str[i];
			}

			typedef mat_t::elem_type elem_type;

			size_t d = (str.length()/sizeof(elem_type));
			size_t n = d%4;

			size_t bufLen = d + n;

			std::wstring result( bufLen, 0 );
			wchar_t * buf = (wchar_t*)result.c_str();

			elem_type * s = (elem_type*)str.c_str();

			for( size_t i=0; i<(d/4); ++i )
			{
				mat_t m;

				m.a = s[i*4+0];
				m.b = s[i*4+1];
				m.c = s[i*4+2];
				m.d = s[i*4+3];

				m = !m;

				memcpy_s( buf+i*4, 8, m.str().c_str(), 8 );
			}

			for( size_t i=0; i < n; ++i )
				buf[d-n+i] = (wchar_t)s[d-n+i];

			return result;
		}
	}
}